package com.supermap.desktop.develop.workspacemigration.migration;

import com.supermap.data.*;
import com.supermap.desktop.core.Application;
import com.supermap.desktop.core.Interface.IOutput;
import com.supermap.desktop.develop.workspacemigration.migration.events.MigrateSteppedEvent;

import java.util.ArrayList;
import java.util.Vector;

public abstract class WorkspaceMigration {

    private final ArrayList<Workspace> srcWorkspaces;
    private final ArrayList<Workspace> tarWorkspaces;

    private transient Vector<SteppedListener> steppedListeners;
    protected transient long totalTasksCount;
    protected transient long processedTasksCount;
    protected transient long subTasksCount;
    protected transient long processedSubTasksCount;

    protected WorkspaceMigration() {
        srcWorkspaces = new ArrayList<>();
        tarWorkspaces = new ArrayList<>();
    }

    public ArrayList<Workspace> getSrcWorkspaces() {
        return srcWorkspaces;
    }

    public ArrayList<Workspace> getTarWorkspaces() {
        return tarWorkspaces;
    }

    public void dispose() {
        srcWorkspaces.clear();
        tarWorkspaces.clear();
        steppedListeners.clear();
    }

    public void initWorkspaces() {
        initWorkspacesCore();
    }

    protected abstract void initWorkspacesCore();

    public boolean migrate() {
        totalTasksCount = 0;
        processedTasksCount = 0;
        subTasksCount = 0;
        processedSubTasksCount = 0;

        long totalDatasetsCount = getToMigratedDatasetsCount();
        int totalResourcesCount = 0;
        int totalMapsCount = 0;
        int totalScenesCount = 0;
        int totalLayoutsCount = 0;
        int totalWorkspacesCount = 0;
        for (Workspace srcWorkspace : srcWorkspaces) {
            totalResourcesCount += 3;
            totalMapsCount += srcWorkspace.getMaps().getCount();
            totalScenesCount += srcWorkspace.getScenes().getCount();
            totalLayoutsCount += srcWorkspace.getLayouts().getCount();
            totalWorkspacesCount++;
        }
        totalTasksCount = totalDatasetsCount + totalResourcesCount + totalMapsCount + totalScenesCount + totalLayoutsCount + totalWorkspacesCount;

        IOutput output = Application.getActiveApplication().getOutput();

        try {
            processedSubTasksCount = 0;
            subTasksCount = totalDatasetsCount;
            if (totalTasksCount > 0 && subTasksCount > 0) {
                fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                        (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                        "正在迁移数据源中......", "migrate", false));
            }
            if (!migrateDatasources(srcWorkspaces, tarWorkspaces)) {
                output.output("迁移数据源失败！");
                processedSubTasksCount = subTasksCount;
                processedTasksCount = totalDatasetsCount + totalResourcesCount + totalMapsCount + totalScenesCount + totalLayoutsCount;
                if (totalTasksCount > 0 && subTasksCount > 0) {
                    fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                            (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                            "迁移数据源完成...", "migrate", false));
                }
            } else {
                if (totalTasksCount > 0 && subTasksCount > 0) {
                    fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                            (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                            "迁移数据源完成...", "migrate", false));
                }

                processedSubTasksCount = 0;
                subTasksCount = totalResourcesCount;
                if (totalTasksCount > 0 && subTasksCount > 0) {
                    fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                            (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                            "正在迁移资源库中......", "migrate", false));
                    if (!migrateResources(srcWorkspaces, tarWorkspaces)) {
                        output.output("迁移资源库失败！");
                        processedSubTasksCount = subTasksCount;
                        processedTasksCount = totalDatasetsCount + totalResourcesCount;
                    }
                    fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                            (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                            "迁移资源库完成...", "migrate", false));
                }

                processedSubTasksCount = 0;
                subTasksCount = totalMapsCount;
                if (totalTasksCount > 0 && subTasksCount > 0) {
                    fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                            (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                            "正在迁移地图中......", "migrate", false));
                    if (!migrateMaps(srcWorkspaces, tarWorkspaces)) {
                        output.output("迁移地图失败！");
                        processedSubTasksCount = subTasksCount;
                        processedTasksCount = totalDatasetsCount + totalResourcesCount + totalMapsCount;
                    }
                    fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                            (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                            "迁移地图完成...", "migrate", false));
                }

                processedSubTasksCount = 0;
                subTasksCount = totalScenesCount;
                if (totalTasksCount > 0 && subTasksCount > 0) {
                    fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                            (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                            "正在迁移场景中......", "migrate", false));
                    if (!migrateScenes(srcWorkspaces, tarWorkspaces)) {
                        output.output("迁移场景失败！");
                        processedSubTasksCount = subTasksCount;
                        processedTasksCount = totalDatasetsCount + totalResourcesCount + totalMapsCount + totalScenesCount;
                    }
                    fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                            (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                            "迁移场景完成...", "migrate", false));
                }

                processedSubTasksCount = 0;
                subTasksCount = totalWorkspacesCount;
                if (totalTasksCount > 0 && subTasksCount > 0) {
                    fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                            (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                            "正在迁移布局中......", "migrate", false));
                    if (!migrateLayouts(srcWorkspaces, tarWorkspaces)) {
                        output.output("迁移布局失败！");
                        processedSubTasksCount = subTasksCount;
                        processedTasksCount = totalDatasetsCount + totalResourcesCount + totalMapsCount + totalScenesCount + totalLayoutsCount;
                    }
                    fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                            (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                            "迁移布局完成...", "migrate", false));
                }
            }
        } catch (Exception e) {
            output.output(e);
        }

        processedSubTasksCount = 0;
        fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                (int) processedSubTasksCount, 0, "迁移工作空间", "迁移总进度",
                "正在迁移工作空间中......", "migrate", false));
        boolean migrateResult = migrateWorkspaces(srcWorkspaces, tarWorkspaces);
        if (!migrateResult) {
            processedSubTasksCount = subTasksCount;
            processedTasksCount = totalTasksCount;
        }
        fireStepped(new MigrateSteppedEvent(this, (int) (processedTasksCount * 100 / totalTasksCount),
                (int) (processedSubTasksCount * 100 / subTasksCount), 0, "迁移工作空间", "迁移总进度",
                "迁移工作空间完成...", "migrate", false));
        return migrateResult;
    }

    protected abstract boolean migrateDatasources(ArrayList<Workspace> srcWorkspaces, ArrayList<Workspace> tarWorkspaces);

    protected abstract boolean migrateResources(ArrayList<Workspace> srcWorkspaces, ArrayList<Workspace> tarWorkspaces);

    protected abstract boolean migrateMaps(ArrayList<Workspace> srcWorkspaces, ArrayList<Workspace> tarWorkspaces);

    protected abstract boolean migrateScenes(ArrayList<Workspace> srcWorkspaces, ArrayList<Workspace> tarWorkspaces);

    protected abstract boolean migrateLayouts(ArrayList<Workspace> srcWorkspaces, ArrayList<Workspace> tarWorkspaces);

    protected abstract boolean migrateWorkspaces(ArrayList<Workspace> srcWorkspaces, ArrayList<Workspace> tarWorkspaces);

    protected static WorkspaceType getWorkspaceType(EngineType engineType) {
        WorkspaceType workspaceType = null;

        if (engineType == EngineType.POSTGRESQL) {
            workspaceType = WorkspaceType.PGSQL;
        } else if (engineType == EngineType.PGGIS) {
            workspaceType = WorkspaceType.PGIS;
        } else if (engineType == EngineType.DM) {
            workspaceType = WorkspaceType.DM;
        }

        return workspaceType;
    }

    protected void fireStepped(MigrateSteppedEvent event) {
        if (steppedListeners != null) {
            Vector<SteppedListener> vector = this.steppedListeners;
            int i = vector.size();
            for (byte b = 0; b < i; b++)
                vector.elementAt(b).stepped(event);
        }
    }

    protected long getToMigratedDatasetsCount() {
        long totalDatasetsCount = 0;
        ArrayList<String> datasourceAliasList = new ArrayList<>();
        for (Workspace srcWorkspace : srcWorkspaces) {
            Datasources datasources = srcWorkspace.getDatasources();
            for (int i = 0; i < datasources.getCount(); i++) {
                Datasource datasource = datasources.get(i);
                String alias = datasource.getAlias();
                if (!datasourceAliasList.contains(alias)) {
                    totalDatasetsCount += datasource.getDatasets().getCount();
                    datasourceAliasList.add(alias);
                }
            }
        }
        datasourceAliasList.clear();
        return totalDatasetsCount;
    }

    public synchronized void addSteppedListener(SteppedListener steppedListener) {
        if (steppedListeners == null) {
            steppedListeners = new Vector<>();
        }
        if (!steppedListeners.contains(steppedListener)) {
            steppedListeners.add(steppedListener);
        }
    }

    public synchronized void removeSteppedListener(SteppedListener steppedListener) {
        if (steppedListeners != null && steppedListeners.contains(steppedListener)) {
            steppedListeners.remove(steppedListener);
        }
    }
}